/**
 * ATuanZhang
 */
package org.huanglei.android.inject;

import java.lang.reflect.Field;

import javax.annotation.Nullable;

import org.huanglei.android.inject.annotation.InjectResource;

import android.content.Context;

import com.google.inject.MembersInjector;
import com.google.inject.Provider;
import com.google.inject.TypeLiteral;
import com.google.inject.spi.TypeEncounter;
import com.google.inject.spi.TypeListener;

/**
 * @author huanglei
 * @date 2011-3-30 @
 */
public class ResourceListener implements TypeListener {

	protected Provider<Context> contextProvider = null;

	/**
	 * 
	 */
	public ResourceListener(Provider<Context> contextProvid) {
		this.contextProvider = contextProvid;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * com.google.inject.spi.TypeListener#hear(com.google.inject.TypeLiteral,
	 * com.google.inject.spi.TypeEncounter)
	 */
	@Override
	public <I> void hear(TypeLiteral<I> typeLiteral,
			TypeEncounter<I> typeEncounter) {
		for (Field field : typeLiteral.getRawType().getDeclaredFields()) {
			if (field.isAnnotationPresent(InjectResource.class)) {
				typeEncounter.register(new ResourceMembersInject<I>(field,
						field.getAnnotation(InjectResource.class)));
			}
		}

	}

}

class ResourceMembersInject<T> implements MembersInjector<T> {

	protected Field field = null;
	protected InjectResource annotation = null;

	/**
	 * 
	 */
	public ResourceMembersInject(Field field, InjectResource annotation) {
		this.field = field;
		this.annotation = annotation;
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see com.google.inject.MembersInjector#injectMembers(java.lang.Object)
	 */
	@Override
	public void injectMembers(T instance) {

		Object value = null;

		if (value == null && field.getAnnotation(Nullable.class) == null)
			throw new NullPointerException(
					String.format(
							"Can't inject null value into %s.%s when field is not @Nullable",
							field.getDeclaringClass(), field.getName()));

		field.setAccessible(true);
		try {
			field.set(instance, value);
		} catch (IllegalArgumentException e) {
			throw new RuntimeException(e);
		} catch (IllegalAccessException e) {
			throw new IllegalArgumentException(String.format(
					"Can't assign %s value %s to %s field %s",
					value != null ? value.getClass() : "(null)", value, field
							.getType(), field.getName()));
		}
	}

}
